package com.zzx.threekingdom.judge;


import com.zzx.threekingdom.activity.PlayActivity;
import com.zzx.threekingdom.card.Card;
import com.zzx.threekingdom.card.CardHeap;
import com.zzx.threekingdom.card.CardList;
import com.zzx.threekingdom.card.CharacterCard;
import com.zzx.threekingdom.card.KnowhowCard;
import com.zzx.threekingdom.card.PatternCard;
import com.zzx.threekingdom.card.KnowhowCard.KnowhowCardType;
import com.zzx.threekingdom.judge.Rule.CardRule;
import com.zzx.threekingdom.judge.Rule.PlayerStep;
import com.zzx.threekingdom.model.AbsPlayerModel;
import com.zzx.threekingdom.model.ActionInfo;
import com.zzx.threekingdom.model.AiPlayerModel;
import com.zzx.threekingdom.model.Damage;
import com.zzx.threekingdom.model.UserPlayerModel;
import com.zzx.threekingdom.view.LogTextBox;
import com.zzx.threekingdom.view.OtherPlayersView;
import com.zzx.threekingdom.view.PlayerView;

import android.app.AlertDialog;
import android.os.Handler;
import android.os.Message;



import java.util.ArrayList;

public class Judge
{
    public static final int MSGID_PLAYERMODEL_DONE = 0;
    
    public interface IPassCards { void onGotCards(CardList cards); }
    public interface IPassCard { void onGotCard(Card card); }
    public interface IPassAction { void onGotAction(ActionInfo act); }
    public interface IAskYesNo { void onResult(boolean yes); }

    public static Judge judge ;
    
    public int CurrentPMIndex = 0;
    public PlayerStep CurrentPlayerStep = PlayerStep.turnEnd;
    public ArrayList<AbsPlayerModel> playerModelList = new ArrayList<AbsPlayerModel>();//counter-clockwise
    public MyTurnHandler mTurnHandler = new MyTurnHandler();
    public boolean bIsGameRunning = false;
    public LogTextBox mLogTextBox = null;
    public PlayActivity playActivity = null;
    
    private AskPeach askPeach = new AskPeach();
    private AskImpeccable askImpeccable = new AskImpeccable();
    private AskOtherEach askOtherEach  = new AskOtherEach();
    private Harvest askHarvest = new Harvest();
    private AllPeach allPeach = new AllPeach();
    
    private Judge()
    {
        clear();
        CardHeap.cardHeap.playCards.shuffle();
        CardHeap.cardHeap.characterCards.shuffle();
    }
    
    public static void reload()
    {
        CardHeap.reload();
        if(judge!=null)
            judge.clear();
        judge = null;
        judge = new Judge();
    }
    
    public void clear()
    {
        mLogTextBox = null;
        bIsGameRunning = false;
        CurrentPMIndex = 0;
        mTurnHandler.clear();
    }
    
    public boolean isGameEnd()
    {
        if((bIsGameRunning==true)&&((getLivePlayers()<=1)||(CardHeap.cardHeap.playCards.size()==0)))
        {
            stopGame();
            ArrayList<AbsPlayerModel> pms = getLivePm();
            if(pms.size()==1)
            {
                endGameByWinner(pms.get(0));
            }
            else if(CardHeap.cardHeap.playCards.size()==0)
                endGameByText("牌摸光，游戏结束");
            else
                endGameByText("无人永生");
            return true;
        }
        return false;
    }
    
    public void stopGame()
    {
        if(bIsGameRunning==true)
        {
            bIsGameRunning = false;
            mTurnHandler.clear();
            addLog("游戏结束");
        }
    }
    
    public int getIndexByPlayer(AbsPlayerModel pm)
    {
        for(int count = 0;count < playerModelList.size();count++)
        {
            if(pm==playerModelList.get(count))
                return count;
        }
        return 0;
    }

    public AbsPlayerModel getModelByPlayerView(PlayerView playerView)
    {
        for(int count = 0;count < playerModelList.size();count++)
        {
            AbsPlayerModel pm = playerModelList.get(count); 
            if(pm.getPlayerView()==playerView)
                return pm;
        }
        return null;
    }
    
    public ArrayList<AbsPlayerModel> Pv2Pm(ArrayList<PlayerView> pvs)
    {
        ArrayList<AbsPlayerModel> pms = new ArrayList<AbsPlayerModel>();
        for(int i = 0; i < pvs.size() ;i++)
        {
            AbsPlayerModel pm = getModelByPlayerView(pvs.get(i));
            if(pm != null)
                pms.add(pm);
        }
        return pms;
    }
    
    public void setCurrentTurnPlayerModelIndex(int index) { CurrentPMIndex = index; }
    public AbsPlayerModel getCurrentTurnPlayer() { return playerModelList.get(CurrentPMIndex); }
    public PlayerStep getCurrentTurnPlayerStep() { return CurrentPlayerStep; }
    public boolean isCurrentTurn(AbsPlayerModel pm) { return (getCurrentTurnPlayer()==pm); }
    public boolean isCurrentStep(PlayerStep ps) { return (CurrentPlayerStep==ps); }
    public boolean IsGameRunning() { return bIsGameRunning; };
    public void askForPeach(AbsPlayerModel pm, Runnable doneR) { askPeach.beginAsk(pm, doneR); };
    public void setLogTextBox(LogTextBox ltb) { mLogTextBox = ltb; }
    public void addLog(String log)
    {
        if(mLogTextBox!=null)
            mLogTextBox.appendLog(log + "\n");
    }
    
    public boolean postDone(Runnable r) { return (r!=null)?mTurnHandler.post(r):false; }
    public void askImpeccable(AbsPlayerModel from, String action, AbsPlayerModel to, IAskYesNo iAsk) { askImpeccable.beginAsk(from, action, to, iAsk); }
    
    public void endGame(AlertDialog d)
    {
        
        d.show();
        playActivity = null;
        bIsGameRunning = false;
    }
    
    public void endGameByText(String str)
    {
        AlertDialog d = playActivity.endGame();
        d.setMessage(str);
        endGame(d);

    }
    
    public void endGameByWinner(AbsPlayerModel pm)
    {
        AlertDialog d = playActivity.endGame();
        d.setMessage(pm.getCharacterName() + " " + "获胜");
        endGame(d);

    }
    
    public boolean startGame(PlayActivity p, OtherPlayersView otherPlayersView, int playerNum)
    {
        if(p==null||playerNum<2)
            return false;
        playActivity = p;
        bIsGameRunning = true;
        playerModelList.clear();
        
        for(int i = 0;i < playerNum - 1;i++)
        {
            playerModelList.add(new AiPlayerModel(otherPlayersView.addNewPlayerView()));
        }
        CardList backCards = new CardList();
        final PutCardBack putCharacterCardBack = new PutCardBack(backCards);
        
        CardHeap.cardHeap.playCards.shuffle();
        CardHeap.cardHeap.characterCards.shuffle();
        
        final UserPlayerModel pm = new UserPlayerModel(p);
        playerModelList.add(pm);
        CardList playerCard = CardHeap.cardHeap.characterCards.drawCards(4);
        putCharacterCardBack.putBackCards(playerCard);
        IPassCard ipc = new IPassCard()
        {
            public void onGotCard(Card card)
            {
                if(Card.isCardValid(card)==false)
                {
                    endGameByText("无效卡");
                }
                pm.setCharacter((CharacterCard)card);
                addLog("玩家选择" + card.name);
                
                for(int count = 0;count < playerModelList.size();count++)
                {
                    CardList cards = CardHeap.cardHeap.characterCards.drawCards(4);
                    putCharacterCardBack.putBackCards(cards);
                    final AbsPlayerModel pModel = playerModelList.get(count); 
                    if(pModel!=pm)
                    {
                        IPassCard ipc = new IPassCard()
                        {
                            public void onGotCard(Card card)
                            {
                                if(Card.isCardValid(card)==false)
                                {
                                    endGameByText("无效卡");
                                }
                                pModel.setCharacter((CharacterCard)card);
                                addLog("ai选择" + card.name);
                            }
                        };
                        pModel.pickOneCharacter(cards, ipc);
                    }
                }
                postDone(putCharacterCardBack);
                
                onStartDistributionCards();
            }
        };
        pm.pickOneCharacter(playerCard, ipc);
        
        return true;
    }
    
    public void onStartDistributionCards()
    {
        for(int count = 0;count < playerModelList.size();count++)
        {
            AbsPlayerModel pm = playerModelList.get(count);
            pm.addHandCards(CardHeap.cardHeap.drawPlayCards(4));
        }
        onStartTurn();
        
    }
    public int getLivePlayers()
    {
        int ret = playerModelList.size();
        for(int count = 0;count < playerModelList.size();count++)
        {
            if(playerModelList.get(count).isDead())
                ret--;
        }
        return ret;
    }
    public ArrayList<AbsPlayerModel> getLivePm()
    {
        ArrayList<AbsPlayerModel> retPm = new ArrayList<AbsPlayerModel>();
        for(int count = 0;count < playerModelList.size();count++)
        {
            AbsPlayerModel pm = playerModelList.get(count);
            if(pm.isDead()==false)
                retPm.add(pm);
        }
        
        return retPm;
    }
    
    
    public ArrayList<AbsPlayerModel> getClockWiseLivePmByIndex(int index)
    {
        ArrayList<AbsPlayerModel> retPm = new ArrayList<AbsPlayerModel>();
        for(int count = 0;count < playerModelList.size();count++)
        {
            if(index>(playerModelList.size() - 1))
                index = 0;
            
            AbsPlayerModel pm = playerModelList.get(index++);
            if(pm.isDead()==false)
                retPm.add(pm);
        }
        
        return retPm;
    }
    
    public ArrayList<AbsPlayerModel> getLivePmFromeMe(AbsPlayerModel me)    //except me
    {
        int indexMe = playerModelList.indexOf(me);
        if(indexMe == -1)
            return new ArrayList<AbsPlayerModel>();

        ArrayList<AbsPlayerModel> retPm = getClockWiseLivePmByIndex(indexMe);
        retPm.remove(me);
        return retPm;
    }
    
    public ArrayList<AbsPlayerModel> getLivePmFromeCurrentTurn()
    {
        AbsPlayerModel pm = getCurrentTurnPlayer();
        if(pm.isDead()==true)
            pm = getNextLivePlayerModel();
        int indexFirst = playerModelList.indexOf(pm);
        if(indexFirst < 0)
            return new ArrayList<AbsPlayerModel>();
        ArrayList<AbsPlayerModel> retPm = getClockWiseLivePmByIndex(indexFirst);
        return retPm;
    }
    
    public AbsPlayerModel getNextLivePlayerModel()
    {
        if(isGameEnd()==true)
            return null;
        AbsPlayerModel pm = null;
        if(CurrentPMIndex + 1 < playerModelList.size())
        {
            pm = playerModelList.get(CurrentPMIndex + 1);
        }
        else
        {
            CurrentPMIndex = 0;
            pm = playerModelList.get(0);
        }
        while((pm!=null)&&(pm.isDead()))
        {
            pm = getNextLivePlayerModel();
        }
        return pm;
    }
    
    
    private AbsPlayerModel turnToNextLivePlayerModel()
    {
        if(isGameEnd()==true)
            return null;
        AbsPlayerModel pm = null;
        if(CurrentPMIndex + 1 < playerModelList.size())
        {
            pm = playerModelList.get(++CurrentPMIndex);
        }
        else
        {
            CurrentPMIndex = 0;
            pm = playerModelList.get(0);
        }
        while((pm!=null)&&(pm.isDead()))
        {
            pm = getNextLivePlayerModel();
        }
        return pm;
    }
    
    
    public void getOneJudgeCard(ActionInfo actInfo, IPassCard ipc)
    {
        CardList cards = CardHeap.cardHeap.drawPlayCards(1);
        Card judgeCard = null;
        if(cards.size() != 0)
        {
            judgeCard = cards.get(0);
            addLog(actInfo.getHintText() + "的判定牌是" + Card.getCardDescription(judgeCard));
            
            //TODO 是否修改判定牌
        }
        
        if(ipc != null)
            ipc.onGotCard(judgeCard);
        
        CardHeap.cardHeap.addTrashCard(judgeCard);

    }
    
    
    public void executeKill(final ActionInfo act, final Runnable doneRunnable)
    {
    	final ArrayList<AbsPlayerModel> targetPms = act.getTargetPms();
    	Card useCard = act.getCard();
    	
    	
        if(targetPms.size()!=0)
        {
            String cardName = Card.getCardDescription(useCard);
            final AbsPlayerModel targetPm = targetPms.get(0);
            addLog(act.getFrom().getCharacterName() + "对" + targetPms.get(0) + "打出杀"  + "("+ cardName!=null?cardName:"" + ")");
            
    		if(targetPm.hasEquipment("仁王盾")==true)
    		{
    			if(PatternCard.isRed(act.getCard())==true)
    			{
    				addLog(targetPm.getCharacterName() + "的仁王盾抵御黑色杀, 不用出闪");
    				postDone(doneRunnable);
    				return;
    			}
    		}
            
            IPassAction ipa = new IPassAction() { public void onGotAction(ActionInfo act) {
				if(act!=null&&act.getActionName().equals("闪"))
				{
					String cardName = Card.getCardDescription(act.getCard());
                    addLog(targetPm.getCharacterName() + "使用了" + cardName!=null?cardName:"闪");
                    if(act.getCard() != null)
                    	targetPm.drawCard(act.getCard());
				}
				else
                {
                    addLog(targetPm.getCharacterName() + "放弃");
                    targetPm.onDamage(new Damage(act), null);
                }
				targetPms.remove(0);
                executeKill(act, doneRunnable);
            }};
            targetPm.onHintText("请出闪否则掉血");
            targetPm.onNeedActionByName("闪", ipa, null);
        }
        else
            postDone(doneRunnable);
    }
    
    public void executeDuel(final AbsPlayerModel from, final AbsPlayerModel to, final Runnable doneRunnable)
    {
    	IPassAction ipa = new IPassAction() { public void onGotAction(ActionInfo act) {
				if(act!=null&& act.getActionName().equals("杀"))
				{
					executeDuel(to, from, doneRunnable);
				}
				else
				{
					to.onDamage(new Damage(new ActionInfo(from, to, "决斗", null)), doneRunnable);
				}
			}
    	};
    	
        to.onNeedActionByName("杀", ipa, new ActionInfo(from, to, "决斗", null));
    }
    
    public void activeAct(final ActionInfo act, final Runnable doneRunnable)
    {
        if(act==null||act.getActionName()==null||act.isTargetValid()==false||(act.getFrom()==null))
        {
            addLog("无效出牌");
            postDone(doneRunnable);
            return;
        }
        
        String actionName = act.getActionName();
        KnowhowCardType knowhowCardType = KnowhowCard.string2Type(actionName);
        if(knowhowCardType != KnowhowCardType.NA)
        {
            if(CardRule.isImmediateKnowhowType(knowhowCardType)==true)
            {
                if(knowhowCardType == KnowhowCardType.outofnothing)
                {
                    IAskYesNo iAsk = new IAskYesNo()
                    {
                        public void onResult(boolean yes)
                        {
                            if(yes==false)
                            {
                                AbsPlayerModel pm = act.getFrom();
                                CardList cards = CardHeap.cardHeap.drawPlayCards(2);
                                Judge.judge.addLog(pm.getCharacterName() + "从牌堆里摸了" + cards.size() + "张牌");
                                pm.addHandCards(cards);
                            }
                            postDone(doneRunnable);
                        }
                    };
                    askImpeccable.beginAsk(act.getFrom(), actionName, null, iAsk);

                }
                else if(knowhowCardType == KnowhowCardType.harvest)
                {
                	askHarvest.beginAsk(act, doneRunnable);
                }
                else if(knowhowCardType == KnowhowCardType.duel)
                {
                    IAskYesNo iAsk = new IAskYesNo()
                    {
                        public void onResult(boolean yes)
                        {
                            if(yes==false)
                            	executeDuel(act.getFrom(), act.getTo(), doneRunnable);
                            else
                            	postDone(doneRunnable);
                        }
                    };
                    askImpeccable.beginAsk(act.getFrom(), actionName, null, iAsk);
                    
                    
                }
                else if(knowhowCardType == KnowhowCardType.allpeach)
                {
                	allPeach.beginAsk(act, doneRunnable);
                }
                else if(knowhowCardType == KnowhowCardType.alieninvade)
                {
                	askOtherEach.beginAsk(act, doneRunnable);
                }
                else if(knowhowCardType == KnowhowCardType.swarmofarrows)
                {
                	askOtherEach.beginAsk(act, doneRunnable);
                }
                else if(knowhowCardType == KnowhowCardType.steal)
                {
                	if(CardList.getCardssCardNum(act.getOneTarget().getAllCards())==0)
                	{
                		postDone(doneRunnable);
                		return;
                	}                	
                	IAskYesNo iAsk = new IAskYesNo()
                    {
                        public void onResult(boolean yes)
                        {
                            if(yes==false)
                            {
                            	IPassCard ipc = new IPassCard() {
									public void onGotCard(Card card) {
										if(card != null)
										{
											act.getOneTarget().drawCard(card);
											addLog(act.getFrom().getCharacterName() + "拿走" + act.getTo().getCharacterName() + "的牌" + Card.getCardDescription(card));
											act.getFrom().addHandCards(new CardList().addCard(card));
										}
										postDone(doneRunnable);
									}
                            		
                            	};
                            	act.getFrom().pickTargetOneCard(act.getTo().getAllCards(), ipc);
                            }
                            else
                            	postDone(doneRunnable);
                        }
                    };
                    askImpeccable.beginAsk(act.getFrom(), actionName, act.getOneTarget(), iAsk);
                }
                else if(knowhowCardType == KnowhowCardType.remove)
                {
                	if(CardList.getCardssCardNum(act.getOneTarget().getAllCards())==0)
                	{
                		postDone(doneRunnable);
                		return;
                	}                	
                	IAskYesNo iAsk = new IAskYesNo()
                    {
                        public void onResult(boolean yes)
                        {
                            if(yes==false)
                            {
                            	IPassCard ipc = new IPassCard() {
									public void onGotCard(Card card) {
										if(card != null)
										{
											act.getOneTarget().drawCard(card);
											addLog(act.getFrom().getCharacterName() + "拆掉" + act.getTo().getCharacterName() + "的牌" + Card.getCardDescription(card));
											
										}
										postDone(doneRunnable);
									}
                            	};
                            	act.getFrom().pickTargetOneCard(act.getTo().getAllCards(), ipc);
                            }
                            else
                            	postDone(doneRunnable);
                        }
                    };
                    askImpeccable.beginAsk(act.getFrom(), actionName, act.getOneTarget(), iAsk);
                }
                else
                    postDone(doneRunnable);
                
            }
        }
        else if(actionName.equals("杀"))
        {
        	act.getFrom().setHasUsedKill(true);
            executeKill(act, doneRunnable);
        }
        else
            postDone(doneRunnable);

        
    }
    
    public void onStartTurn()
    {
        CurrentPMIndex = 0;
        mTurnHandler.onStartCurrentPlayerModelTurn();
    }
    
    public void onEnterPlayerStep(final AbsPlayerModel pm, PlayerStep playerStep, Message doneMsg)
    {
        addLog(pm.getCharacterName() + "进入" + Rule.getStepName(playerStep) + "阶段");
        pm.onEnterPlayerStep(playerStep, doneMsg);
    }
    
    private class PutCardBack implements Runnable
    {
        public PutCardBack(CardList backCards)
        {
            mBackCards = backCards;
        }
        
        public CardList mCards = new CardList();
        public CardList mBackCards = null;
        public void putBackCards(CardList cards) { mCards.addCards(cards); }
        
        public void run()
        {
            if(mBackCards!=null)
                mBackCards.addCards(mCards);
        }
    }
    
    public static void sendStepDoneMsg(AbsPlayerModel pm, Message msg)
    {
        msg.obj = pm;
        ((MyTurnHandler)msg.getTarget()).sendMessageDelayed(msg, 300);
    }
    
    public static void sendStepDoneMsgWithoutDelay(AbsPlayerModel pm, Message msg)
    {
        if(msg != null)
        {
            msg.obj = pm;
            ((MyTurnHandler)msg.getTarget()).sendMessage(msg);
        }
    }
    
    public static void sendCountDoneMsg(Message msg)
    {
        msg.what = MyTurnHandler.COUNT_DONEMSG_WHAT;
        msg.sendToTarget();
    }
    
    
    
    private class MyTurnHandler extends Handler
    {
        private Message mWaitingMsg;
        public static final int DONEMSG_WHAT = 1;
        public static final int COUNT_DONEMSG_WHAT = 2;
        
        public Message newDoneMsg()
        {
            mWaitingMsg = obtainMessage();
            mWaitingMsg.what = DONEMSG_WHAT;
            return mWaitingMsg;
        }
        
        public void clear()
        {
            removeMessages(DONEMSG_WHAT);
            mWaitingMsg = null;
        }
        
        public void onStartCurrentPlayerModelTurn()
        {
            AbsPlayerModel pm = playerModelList.get(CurrentPMIndex);
            CurrentPlayerStep = PlayerStep.turnBegin;
            Judge.this.onEnterPlayerStep(pm, PlayerStep.turnBegin, newDoneMsg());
        }
        
        public void handleMessage (Message msg)
        {
            if(isGameEnd()==true)
                return;
            
            if((msg==mWaitingMsg)&&(msg.what == DONEMSG_WHAT))
            {
                AbsPlayerModel pm = playerModelList.get(CurrentPMIndex);
                if(msg.obj!=pm)
                    return;
                
                if(CurrentPlayerStep != PlayerStep.turnEnd)
                {
                    CurrentPlayerStep = Rule.getNextStep(CurrentPlayerStep);
                    
                    ArrayList<PlayerStep> jump = pm.getJumpStep();
                    
                    while(jump.contains(CurrentPlayerStep))
                    {
                        jump.remove(CurrentPlayerStep);
                        CurrentPlayerStep = Rule.getNextStep(CurrentPlayerStep);
                    }
                                        
                    Judge.this.onEnterPlayerStep(pm, CurrentPlayerStep, newDoneMsg());
                }
                else
                {
                    pm.onOutOfTurn();
                    CurrentPMIndex = getIndexByPlayer(turnToNextLivePlayerModel());
                    onStartCurrentPlayerModelTurn();
                }
            }
        }

    }

    
}
